home *** CD-ROM | disk | FTP | other *** search
/ Shareware Super Platinum 8 / Shareware Super Platinum 8.iso / mac / PROGTOOL / GWMALLOC.ZIP;1 / GWMALLOC.TAR / gw_malloc / malloc_dbg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-08  |  12.9 KB  |  514 lines

  1. /*
  2.  * program that handles the malloc debug variables.
  3.  *
  4.  * Copyright 1992 by Gray Watson and the Antaire Corporation
  5.  *
  6.  * This file is part of the malloc-debug package.
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Library General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2 of the License, or (at your option) any later version.
  12.  *
  13.  * This library is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Library General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Library General Public
  19.  * License along with this library (see COPYING-LIB); if not, write to the
  20.  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  *
  22.  * The author of the program may be contacted at gray.watson@antaire.com
  23.  */
  24.  
  25. /*
  26.  * This is the malloc_dbg program which is designed to enable the user
  27.  * to easily enable the multitude of malloc-debug capabilities.
  28.  *
  29.  * NOTE: all stdout output from this program is designed to be run through
  30.  *   eval by default.  Any messages for the user should be fprintf to stderr.
  31.  */
  32.  
  33. #include <stdarg.h>                /* for vsprintf handling */
  34. #include <stdio.h>                /* for stderr */
  35.  
  36. #define MALLOC_DEBUG_DISABLE
  37.  
  38. #include "malloc.h"
  39. #include "malloc_loc.h"
  40.  
  41. #include "compat.h"
  42. #include "conf.h"
  43. #include "dbg_tokens.h"
  44. #include "version.h"
  45.  
  46. #if INCLUDE_RCS_IDS
  47. LOCAL    char    *rcs_id =
  48.   "$Id: malloc_dbg.c,v 1.6 1993/04/06 04:24:39 gray Exp $";
  49. #endif
  50.  
  51. #define HOME_ENVIRON    "HOME"            /* home directory */
  52. #define DEFAULT_CONFIG    "%s/.mallocrc"        /* default config file */
  53. #define TOKENIZE_CHARS    " \t,="            /* for tag lines */
  54.  
  55. #define USAGE_STRING    "--usage"        /* show the usage message */
  56. #define VERSION_STRING    "--version"        /* show the version message */
  57. #define NO_VALUE    (-1)            /* no value ... value */
  58.  
  59. /* local variables */
  60. LOCAL    char    printed        = FALSE;    /* did we outputed anything? */
  61. LOCAL    char    *program    = NULL;        /* our program name */
  62.  
  63. /* argument variables */
  64. LOCAL    char    *address    = NULL;        /* for ADDRESS */
  65. LOCAL    char    bourne        = FALSE;    /* set bourne shell output */
  66. LOCAL    char    clear        = FALSE;    /* clear variables */
  67. LOCAL    int    debug        = NO_VALUE;    /* for DEBUG */
  68. LOCAL    int    errno_to_print    = NO_VALUE;    /* to print the error string */
  69. LOCAL    char    *inpath        = NULL;        /* for config-file path */
  70. LOCAL    int    interval    = NO_VALUE;    /* for setting INTERVAL */
  71. LOCAL    char    *logpath    = NULL;        /* for LOGFILE setting */
  72. LOCAL    char    *start        = NULL;        /* for START settings */
  73. LOCAL    char    *tag        = NULL;        /* the debug tag */
  74.  
  75. /*
  76.  * hexadecimal STR to long translation
  77.  */
  78. LOCAL    int    hex_to_int(char * str)
  79. {
  80.   int        ret;
  81.   
  82.   /* strip off spaces */
  83.   for (; *str == ' ' || *str == '\t'; str++);
  84.   
  85.   /* skip a leading 0[xX] */
  86.   if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X'))
  87.     str += 2;
  88.   
  89.   for (ret = 0;; str++) {
  90.     if (*str >= '0' && *str <= '9')
  91.       ret = ret * 16 + (*str - '0');
  92.     else if (*str >= 'a' && *str <= 'f')
  93.       ret = ret * 16 + (*str - 'a' + 10);
  94.     else if (*str >= 'A' && *str <= 'F')
  95.       ret = ret * 16 + (*str - 'A' + 10);
  96.     else
  97.       break;
  98.   }
  99.   
  100.   return ret;
  101. }
  102.  
  103. /*
  104.  * print a usage message for the program.
  105.  */
  106. LOCAL    void    usage(void)
  107. {
  108.   (void)fprintf(stderr,    "Usage: %s\n", program);
  109.   (void)fprintf(stderr,    "  [-a address:#]    = stop when malloc sees address "
  110.         "[for #th time] %%s\n");
  111.   (void)fprintf(stderr,    "  [-b]              = set the output for bourne "
  112.         "shells (sh, ksh) %%t\n");
  113.   (void)fprintf(stderr,    "  [-c]              = clear all variables not "
  114.         "specified %%t\n");
  115.   (void)fprintf(stderr,    "  [-d bitmask]      = hex flag to directly set debug "
  116.         "mask %%x\n");
  117.   (void)fprintf(stderr,    "  [-e errno]        = print the error string for "
  118.         "errno %%d\n");
  119.   (void)fprintf(stderr,    "  [-f file]         = config file to read from when "
  120.         "not ~/.mallocrc %%s\n");
  121.   (void)fprintf(stderr, "  [-i number]       = check heap every number times "
  122.         "%%d\n");
  123.   (void)fprintf(stderr,    "  [-l file]         = file to log messages to %%s\n");
  124.   (void)fprintf(stderr, "  [-s file:line]    = start checking heap after "
  125.         "seeing file [and line] %%s\n");
  126.   (void)fprintf(stderr, "  [tag]             = debug token to find in mallocrc"
  127.         "\n");
  128.   (void)fprintf(stderr, "if no arguments are specified then it dumps the "
  129.         "current env setings.\n");
  130. }
  131.  
  132. /*
  133.  * process the command-line arguments
  134.  * I've got a great library to do this automatically.  sigh.
  135.  */
  136. LOCAL    void    process_arguments(int argc, char ** argv)
  137. {
  138.   program = rindex(*argv, '/');
  139.   if (program == NULL)
  140.     program = *argv;
  141.   else
  142.     program++;
  143.   
  144.   argc--, argv++;
  145.   
  146.   for (; argc > 0; argc--, argv++) {
  147.     
  148.     /* special usage message */
  149.     if (strcmp(*argv, USAGE_STRING) == 0) {
  150.       usage();
  151.       exit(0);
  152.     }
  153.     
  154.     /* special version message */
  155.     if (strcmp(*argv, VERSION_STRING) == 0) {
  156.       (void)fprintf(stderr, "Version '%s'\n", malloc_version);
  157.       exit(0);
  158.     }
  159.     
  160.     /* if no - then assume it is the tag */
  161.     if (**argv != '-') {
  162.       if (tag != NULL) {
  163.     (void)fprintf(stderr,
  164.               "Usage problem: debug-tag was already specified\n");
  165.     usage();
  166.     exit(1);
  167.       }
  168.       tag = *argv;
  169.       continue;
  170.     }
  171.     
  172.     /* can only handle -a not -ab */
  173.     if ((*argv)[1] == NULLC || (*argv)[2] != NULLC) {
  174.       (void)fprintf(stderr, "Usage problem: incorrect argument format '%s'\n",
  175.             *argv);
  176.       usage();
  177.       exit(1);
  178.     }
  179.     
  180.     switch ((*argv)[1]) {
  181.       
  182.     case 'a':
  183.       argc--, argv++;
  184.       if (argc == 0) {
  185.     (void)fprintf(stderr, "Usage problem: missing argument to -a\n");
  186.     usage();
  187.     exit(1);
  188.       }
  189.       address = *argv;
  190.       break;
  191.       
  192.     case 'b':
  193.       bourne = TRUE;
  194.       break;
  195.       
  196.     case 'c':
  197.       clear = TRUE;
  198.       break;
  199.       
  200.     case 'd':
  201.       argc--, argv++;
  202.       if (argc == 0) {
  203.     (void)fprintf(stderr, "Usage problem: missing argument to -d\n");
  204.     usage();
  205.     exit(1);
  206.       }
  207.       debug = hex_to_int(*argv);
  208.       break;
  209.       
  210.     case 'e':
  211.       argc--, argv++;
  212.       if (argc == 0) {
  213.     (void)fprintf(stderr, "Usage problem: missing argument to -e\n");
  214.     usage();
  215.     exit(1);
  216.       }
  217.       errno_to_print = atoi(*argv);
  218.       break;
  219.       
  220.     case 'f':
  221.       argc--, argv++;
  222.       if (argc == 0) {
  223.     (void)fprintf(stderr, "Usage problem: missing argument to -f\n");
  224.     usage();
  225.     exit(1);
  226.       }
  227.       inpath = *argv;
  228.       break;
  229.       
  230.     case 'i':
  231.       argc--, argv++;
  232.       if (argc == 0) {
  233.     (void)fprintf(stderr, "Usage problem: missing argument to -i\n");
  234.     usage();
  235.     exit(1);
  236.       }
  237.       interval = atoi(*argv);
  238.       break;
  239.       
  240.     case 'l':
  241.       argc--, argv++;
  242.       if (argc == 0) {
  243.     (void)fprintf(stderr, "Usage problem: missing argument to -l\n");
  244.     usage();
  245.     exit(1);
  246.       }
  247.       logpath = *argv;
  248.       break;
  249.       
  250.     case 's':
  251.       argc--, argv++;
  252.       if (argc == 0) {
  253.     (void)fprintf(stderr, "Usage problem: missing argument to -s\n");
  254.     usage();
  255.     exit(1);
  256.       }
  257.       start = *argv;
  258.       break;
  259.       
  260.     default:
  261.       (void)fprintf(stderr, "Usage problem: unknown argument '%s'\n", *argv);
  262.       usage();
  263.       exit(1);
  264.       break;
  265.     }
  266.   }
  267. }
  268.  
  269. /*
  270.  * process the user configuration looking for the tag.  if tag is null then
  271.  * look for DEBUG_VALUE in the file and return the token for it in STR.
  272.  * routine returns the new debug value matching tag.
  273.  */
  274. LOCAL    int    process(int debug_value, char ** strp)
  275. {
  276.   static char    token[128];
  277.   FILE        *infile = NULL;
  278.   char        path[1024], buf[1024], *homep;
  279.   char        found, cont;
  280.   int        new_debug = 0;
  281.   
  282.   /* do we need to have a home variable? */
  283.   if (inpath == NULL) {
  284.     homep = (char *)getenv(HOME_ENVIRON);
  285.     if (homep == NULL) {
  286.       (void)fprintf(stderr, "%s: could not find variable '%s'\n",
  287.             program, HOME_ENVIRON);
  288.       exit(1);
  289.     }
  290.     
  291.     (void)sprintf(path, DEFAULT_CONFIG, homep);
  292.     inpath = path;
  293.   }
  294.   
  295.   infile = fopen(inpath, "r");
  296.   if (infile == NULL) {
  297.     (void)fprintf(stderr, "%s: could not read '%s': ", program, inpath);
  298.     (void)perror("");
  299.     exit(1);
  300.   }
  301.   
  302.   /* read each of the lines looking for the tag */
  303.   found = FALSE;
  304.   cont = FALSE;
  305.   
  306.   while (fgets(buf, sizeof(buf), infile) != NULL) {
  307.     int        attrc;
  308.     char    *tokp, *endp;
  309.     
  310.     /* ignore comments and empty lines */
  311.     if (buf[0] == '#' || buf[0] == '\n')
  312.       continue;
  313.     
  314.     /* chop off the ending \n */
  315.     endp = rindex(buf, '\n');
  316.     if (endp != NULL)
  317.       *endp = NULLC;
  318.     
  319.     tokp = strtok(buf, TOKENIZE_CHARS);
  320.     
  321.     /* if we're not continuing then we need to process a tag */
  322.     if (! cont) {
  323.       (void)strcpy(token, tokp);
  324.       new_debug = 0;
  325.       
  326.       if (tag != NULL && strcmp(tag, tokp) == 0)
  327.     found = TRUE;
  328.       
  329.       tokp = strtok(NULL, TOKENIZE_CHARS);
  330.     }
  331.     
  332.     cont = FALSE;
  333.     
  334.     do {
  335.       /* do we have a continuation character */
  336.       if (strcmp(tokp, "\\") == 0) {
  337.     cont = TRUE;
  338.     break;
  339.       }
  340.       
  341.       /* are we processing the tag of choice? */
  342.       if (found || tag == NULL) {
  343.     for (attrc = 0; attributes[attrc].at_string != NULL; attrc++) {
  344.       if (strcmp(tokp, attributes[attrc].at_string) == 0)
  345.         break;
  346.     }
  347.     
  348.     if (attributes[attrc].at_string == NULL) {
  349.       (void)fprintf(stderr, "%s: unknown token '%s'\n",
  350.             program, tokp);
  351.     }
  352.     else
  353.       new_debug |= attributes[attrc].at_value;
  354.       }
  355.       
  356.       tokp = strtok(NULL, TOKENIZE_CHARS);
  357.     } while (tokp != NULL);
  358.     
  359.     if (tag == NULL && ! cont && new_debug == debug_value) {
  360.       found = TRUE;
  361.       if (strp != NULL)
  362.     *strp = token;
  363.       break;
  364.     }
  365.     
  366.     /* are we done? */
  367.     if (found && ! cont)
  368.       break;
  369.   }
  370.   
  371.   (void)fclose(infile);
  372.   
  373.   /* did we find the correct value in the file? */
  374.   if (tag == NULL && ! found) {
  375.     if (strp != NULL)
  376.       *strp = "unknown";
  377.   }
  378.   else if (! found && tag != NULL) {
  379.     (void)fprintf(stderr, "%s: could not find tag '%s' in '%s'\n",
  380.           program, tag, inpath);
  381.     exit(1);
  382.   }
  383.   
  384.   return new_debug;
  385. }
  386.  
  387. /*
  388.  * dump the current settings of the malloc variables
  389.  */
  390. LOCAL    void    dump_current(void)
  391. {
  392.   char        *str;
  393.   int        num;
  394.   
  395.   str = (char *)getenv(DEBUG_ENVIRON);
  396.   if (str == NULL)
  397.     (void)fprintf(stderr, "%s not set\n", DEBUG_ENVIRON);
  398.   else {
  399.     num = hex_to_int(str);
  400.     (void)process(num, &str);
  401.     (void)fprintf(stderr, "%s == '%#lx' (%s)\n", DEBUG_ENVIRON, num, str);
  402.   }
  403.   
  404.   str = (char *)getenv(ADDRESS_ENVIRON);
  405.   if (str == NULL)
  406.     (void)fprintf(stderr, "%s not set\n", ADDRESS_ENVIRON);
  407.   else
  408.     (void)fprintf(stderr, "%s == '%s'\n", ADDRESS_ENVIRON, str);
  409.   
  410.   str = (char *)getenv(INTERVAL_ENVIRON);
  411.   if (str == NULL)
  412.     (void)fprintf(stderr, "%s not set\n", INTERVAL_ENVIRON);
  413.   else {
  414.     num = atoi(str);
  415.     (void)fprintf(stderr, "%s == '%d'\n", INTERVAL_ENVIRON, num);
  416.   }
  417.   
  418.   str = (char *)getenv(LOGFILE_ENVIRON);
  419.   if (str == NULL)
  420.     (void)fprintf(stderr, "%s not set\n", LOGFILE_ENVIRON);
  421.   else
  422.     (void)fprintf(stderr, "%s == '%s'\n", LOGFILE_ENVIRON, str);
  423.   
  424.   str = (char *)getenv(START_ENVIRON);
  425.   if (str == NULL)
  426.     (void)fprintf(stderr, "%s not set\n", START_ENVIRON);
  427.   else
  428.     (void)fprintf(stderr, "%s == '%s'\n", START_ENVIRON, str);
  429. }
  430.  
  431. /*
  432.  * output the code to set env VAR to VALUE using printf FORMAT
  433.  */
  434. LOCAL    void    set_variable(char * var, char * format, ...)
  435. {
  436.   char        value[256];
  437.   va_list    args;
  438.   
  439.   /* write the format + info into str */
  440.   va_start(args, format);
  441.   (void)vsprintf(value, format, args);
  442.   va_end(args);
  443.   
  444.   if (bourne)
  445.     (void)printf("%s=%s; export %s;\n", var, value, var);
  446.   else
  447.     (void)printf("setenv %s %s;\n", var, value);
  448.   
  449.   printed = TRUE;
  450. }
  451.  
  452. /*
  453.  * output the code to un-set env VAR
  454.  */
  455. LOCAL    void    unset_variable(char * var)
  456. {
  457.   if (bourne)
  458.     (void)printf("unset %s;\n", var);
  459.   else
  460.     (void)printf("unsetenv %s;\n", var);
  461.   
  462.   printed = TRUE;
  463. }
  464.  
  465. EXPORT    int    main(int argc, char ** argv)
  466. {
  467.   /* turn off debugging for this program */
  468.   (void)malloc_debug(0);
  469.   
  470.   process_arguments(argc, argv);
  471.   
  472.   /* get a new debug value from tag */
  473.   if (tag != NULL) {
  474.     if (debug != NO_VALUE)
  475.       (void)fprintf(stderr, "%s: warning -d option ignored, processing tag "
  476.             "'%s'\n",
  477.             program, tag);
  478.     debug = process(0, NULL);
  479.   }
  480.   
  481.   if (tag != NULL || debug != NO_VALUE)
  482.     set_variable(DEBUG_ENVIRON, "%#lx", debug);
  483.   
  484.   if (address != NULL)
  485.     set_variable(ADDRESS_ENVIRON, "%s", address);
  486.   else if (clear)
  487.     unset_variable(ADDRESS_ENVIRON);
  488.   
  489.   if (interval != NO_VALUE)
  490.     set_variable(INTERVAL_ENVIRON, "%d", interval);
  491.   else if (clear)
  492.     unset_variable(INTERVAL_ENVIRON);
  493.   
  494.   if (logpath != NULL)
  495.     set_variable(LOGFILE_ENVIRON, "%s", logpath);
  496.   else if (clear)
  497.     unset_variable(LOGFILE_ENVIRON);
  498.   
  499.   if (start != NULL)
  500.     set_variable(START_ENVIRON, "%s", start);
  501.   else if (clear)
  502.     unset_variable(START_ENVIRON);
  503.   
  504.   if (errno_to_print != NO_VALUE) {
  505.     (void)fprintf(stderr, "%s: malloc_errno value '%d' = \n",
  506.           program, errno_to_print);
  507.     (void)fprintf(stderr, "   '%s'\n", malloc_strerror(errno_to_print));
  508.   }
  509.   else if (! printed)
  510.     dump_current();
  511.   
  512.   exit(0);
  513. }
  514.